#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstring>
#include <iostream>
#include <memory>
#include <string>

#include "Terminal.hpp"

// 线程数据结构，用于在线程间传递必要的信息
struct ThreadData {
  sockaddr_in local;  // 服务器地址信息
  int sockfd;         // 套接字文件描述符
};

// 打印使用说明
void Usage(std::string proc) {
  std::cout << "\n\tUsage: " << proc << " serverip serverport\n" << std::endl;
}

// 接收消息的线程函数
void* recv_message(void* data) {
  OpenTerminal();
  ThreadData* td = (ThreadData*)data;
  char buffer[1024] = {0};  // 接收缓冲区

  while (true) {
    struct sockaddr_in temp;
    bzero(&temp, sizeof(temp));
    socklen_t len = sizeof(temp);
    // 接收来自服务器的消息
    ssize_t n =
        recvfrom(td->sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);
    if (n > 0) {
      buffer[n] = 0;                     // 确保字符串正确终止
      std::cerr << buffer << std::endl;  // 打印接收到的消息
    }
  }
}

// 发送消息的线程函数
void* send_message(void* data) {
  ThreadData* td = (ThreadData*)data;
  std::string message;

  while (true) {
    std::cout << "Please Enter@";
    getline(std::cin, message);  // 获取用户输入
    socklen_t len = sizeof(td->local);
    // 发送消息到服务器
    int sdebug = sendto(td->sockfd, message.c_str(), message.size(), 0,
                        (struct sockaddr*)&td->local, len);
    if (sdebug < 0) {
      std::cout << "sendto fail, err: " << strerror(errno) << std::endl;
    }
  }
}

int main(int argc, char* argv[]) {
  // 检查命令行参数
  if (argc != 3) {
    Usage(argv[0]);
    exit(0);
  }

  std::string serverip = argv[1];
  uint16_t serverport = std::stoi(argv[2]);
  ThreadData tdata;

  // 初始化服务器地址结构
  bzero(&tdata.local, sizeof(tdata.local));
  tdata.local.sin_family = AF_INET;
  tdata.local.sin_port = htons(serverport);
  tdata.local.sin_addr.s_addr = inet_addr(serverip.c_str());

  // 创建UDP套接字
  tdata.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (tdata.sockfd < 0) {
    std::cout << "socket fail" << std::endl;
    exit(-1);
  }

  // 创建接收和发送线程
  pthread_t recver, sender;
  pthread_create(&recver, nullptr, recv_message, &tdata);
  pthread_create(&sender, nullptr, send_message, &tdata);

  // 等待线程结束（实际上这里的线程不会结束）
  pthread_join(recver, nullptr);
  pthread_join(sender, nullptr);

  // 关闭套接字（实际上这行代码永远不会被执行）
  close(tdata.sockfd);
  return 0;
}
